package com.tiecode.flow.guard;

import com.qiplat.api.framework.common.setting.SettingProvider;
import com.qiplat.api.framework.common.setting.SystemPath;
import com.qiplat.api.plugin.util.PluginEnvironment;
import com.qiplat.develop.util.firstparty.android.AssetUtils;
import com.qiplat.develop.util.firstparty.file.FileUtils;
import com.qiplat.framework.Qiplat;
import com.tiecode.platform.compiler.api.file.FileManager;
import com.tiecode.platform.compiler.api.file.TiecodeTempFile;
import com.tiecode.platform.compiler.api.log.Messager;
import com.tiecode.platform.compiler.api.process.TaskEvent;
import com.tiecode.platform.compiler.api.process.Trees;
import com.tiecode.platform.compiler.source.tree.CompilationUnitTree;
import com.tiecode.platform.compiler.toolchain.completer.RoundEnter;
import com.tiecode.platform.compiler.toolchain.env.Context;
import com.tiecode.platform.compiler.toolchain.env.Options;
import com.tiecode.platform.compiler.toolchain.processor.AnnotationProvider;
import com.tiecode.platform.compiler.toolchain.tree.TCTree;
import com.tiecode.platform.compiler.toolchain.tree.TreePrinter;
import com.tiecode.platform.compiler.toolchain.tree.code.TiecodeTrees;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import cn.tiecode.api.event.TiecodeCompilerEvent;

public final class MyCompilerEvent implements TiecodeCompilerEvent {
    private Context context;
    private SettingProvider settingProvider;

    @Override
    public void init(Context context) {
        this.context = context;
        this.settingProvider = Qiplat.getSettingProvider();
    }

    @Override
    public void onProvideAnnotation(AnnotationProvider annotationProvider) {

    }

    @Override
    public void onEventStarted(TaskEvent event) {
        if (Options.instance(context).outPath == null) {
            return;
        }
        if (event.getKind() == TaskEvent.Kind.ANALYZE) {
            if (settingProvider.getBoolean(MySettingManager.KEY_GUARD_ENABLED, true)) {
                Messager messager = context.get(Messager.key);
                messager.info("执行控制流混淆...");
                modifyControlFlows();
            }
        }
    }

    @Override
    public void onEventFinished(TaskEvent taskEvent) {

    }

    private void modifyControlFlows() {
        boolean logEnabled = settingProvider.getBoolean(MySettingManager.KEY_GUARD_ENABLED, true);
        Trees trees = TiecodeTrees.instance(context);
        List<? extends CompilationUnitTree> units = trees.getCompilationUnits();
        List<TCTree.TCCompilationUnit> newUnits = new ArrayList<>();
        for (CompilationUnitTree unit : units) {
            TCTree.TCCompilationUnit root = (TCTree.TCCompilationUnit) unit;
            if (!root.symbol.name.contentEquals(Options.instance(context).namespace)) {
                continue;
            }
            ControlFlowConfuser confuser = new ControlFlowConfuser(context, logEnabled);
            confuser.modify(root);
            newUnits.add(root);
            printNewUnit(root);
        }
        RoundEnter enter = RoundEnter.instance(context);
        enter.complete(newUnits);
    }

    private void printNewUnit(TCTree.TCCompilationUnit root) {
        TreePrinter printer = new TreePrinter();
        String newCode = printer.getString(root);
        File codeDir = new File(SystemPath.CACHE, "guard_tmp");
        if (!codeDir.exists()) {
            codeDir.mkdirs();
        }
        String name = root.fileObject.getName();
        try {
            FileUtils.writeFile(newCode, new File(codeDir, name));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
